/**
@author		Jong Min, Lee
@date		  10/01/2014
@brief		StudySetPool class 

copyright(c) Tae Young Soft. All right reserved. 2014
*/
#pragma once

#include <list>
#include "Taurus_Util/Macros.h"
#include "Taurus_DcmData/DcmStudy.h"
#include "Taurus_DcmData/StudySet.h"

//forward declarations
class IStudySetInfo;
class IStudyInfo;
class ISeriesInfo;
class IInstanceInfo;
class IFrameInfo;
class CDcmStudy;
class CDcmSeries;
class CDcmInstance;
class CDcmFrame;
class CStudySet;
class CStudy;
class CSeries;
class CInstance;

/**
@brief		studyset pool
*/
class CStudySetPool
{
private:
  /**
  @brief		default constructor
  */
  CStudySetPool();

  DISALLOW_COPY_AND_ASSIGN(CStudySetPool);

public:
  /**
  @brief		destructor
  */
  ~CStudySetPool();

  /**
  @brief		access to pointer to the single instance of study set pool
  @return		pointer to the single instance of study set pool
  */
  static CStudySetPool* getInstance();

  /**
  @brief		create a study set and add it to pool
  @param		studySetInfo pointer to study set information
  @param    media where study set come from
  @param    openMode study set open mode
  @param    outStudySet variable in which pointer to new study set is stored
  @return		ERROR_SUCCESS upon success, an error code otherwise
  */
  DWORD createAndAddStudySet(IStudySetInfo&   studySetInfo,
                             DcmStudyMedia    media,
                             StudySetOpenMode openMode,
                             CStudySet*&      outStudySet);

  /**
  @brief		remove study set from pool
  @param		studySet pointer to study set to be removed
  @return		ERROR_SUCCESS upon success, an error code otherwise
  */
  DWORD removeStudySet(CStudySet* studySet);

  /**
  @brief		remove all study set
  */
  void removeAllStudySet();

private:
  /**
  @brief		initialize study set pool
  */
  void init();

  /**
  @brief		destroy study set pool. this function shoul be only used in destructor
  */
  void destroy();

  /**
  @brief		create a study set
  @param		studySetInfo study set information
  @param    media study media
  @param    openMode study open mode
  @param    outStudySet variable in which pointer to new study set is stored
  @return		ERROR_SUCCESS if succeeds, an error code otherwise
  */
  DWORD createStudySet(IStudySetInfo&   studySetInfo,
                       DcmStudyMedia    media,
                       StudySetOpenMode openMode,
                       CStudySet*&      outStudySet);

  /**
  @brief		create a study
  @param		studyInfo study information
  @param    media study media
  @param    pointer to study set to be parent
  @param    outStudy varaible in which pointer to new study is stored
  @return		ERROR_SUCCESS if succedds, an error code otherwise
  */
  DWORD createStudy(IStudyInfo&       studyInfo,
                    DcmStudyMedia     media,
                    CStudySet*        parent,
                    CStudy*&          outStudy);

  /**
  @brief		create a study
  @param		studyInfo study information
  @param    existenDcmStudy pointer to the existent dcm study
  @param    parent pointer to study set to be parent
  @param    outStudy variable in which pointer to new study is stored
  @return		ERROR_SUCCESS upon success, an error code otherwise
  */
  DWORD createStudy(IStudyInfo&     studyInfo,
                    CDcmStudy*      existentDcmStudy,
                    CStudySet*      parent,
                    CStudy*&        outStudy);

  /**
  @brief		create a dcm series and a series
  @param		seriesInfo series information
  @param    parentStudy pointer to study to be parent of new series
  @param    parentDcmStudy pointer to dcm study to be parent of new dcm series
  @param    outSeries variable in which pointer to new series is stored
  @return		ERROR_SUCCESS upon success, an error code otherwise
  */
  DWORD createSeries(ISeriesInfo&   seriesInfo,
                     CStudy*        parentStudy,
                     CDcmStudy*     parentDcmStudy,
                     CSeries*&      outSeries);

  /**
  @brief		create a series by using existent dcm series
  @param		seriesInfo series information
  @param    existentDcmSeries pointer to existent dcm series
  @param    parent pointer to study to be parent
  @param    outSeries variable in which pointer to new series is stored
  @return		ERROR_SUCCESS if succeeds, an error code otherwise
  */
  DWORD createSeries(ISeriesInfo&   seriesInfo,
                     CDcmSeries*    existentDcmSeries,
                     CStudy*        parent,
                     CSeries*&      outSeries);

  /**
  @brief		add study set to pool
  @param		studySet pointer to study set to be added
  @return		ERROR_SUCCESS if succeeds, an error code otherwise
  */
  DWORD addStudySet(CStudySet* studySet);

  /**
  @brief		destroy a study set.
  @param		studySet pointer to study set to be destroyed
  @return		ERROR_SUCCESS if succeeds, an error code otherwise
  */
  DWORD destroyStudySet(CStudySet* studySet);

  /**
  @brief		find dcm study and remove it from this if possible
  @param		key null-terminated string represents dcm study key
  @return		ERROR_SUCCESS if succeeds, an error code otherwise
  */
  DWORD findAndRemoveDcmStudy(const TCHAR* key);

  /**
  @brief		find dcm study 
  @param		key null-terminated string represents dcm study key
  @return		pointer to dcm study if found, NULL if not
  */
  CDcmStudy* findDcmStudy(const TCHAR* key) const;

  /**
  @brief		add dcm study to pool
  @param		dcmStudy pointer to dcm study
  @return		ERROR_SUCCESS if succeeds, an error code otherwise
  */
  DWORD addDcmStudy(CDcmStudy* dcmStudy);

private:
  //pointer to single instance of studyset pool
  static CStudySetPool* m_theInstance;

  //study set list
  std::list<CStudySet*> m_theStudySets;

  //dcm studies
  std::list<CDcmStudy*> m_theDcmStudies;
};